/*
 *  Common.cpp
 *  
 *
 *  Created by Daniel Fife on 3/25/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#include "Common.h"

#include <ctime>
#include <math.h>
using namespace std;

const double ROOM_WIDTH = 400;
const double ROOM_DEPTH = 400;
const double ROOM_HEIGHT = 96;
const double TABLE_LIFT = 36;

const double TABLE_WIDTH = 46; // 46 inches
const double TABLE_DEPTH = 92; // 92 inches
const double TABLE_HEIGHT = 1.75; // inches
const double TABLE_SLIDING_FRICTION = .2;
const double TABLE_ROLLING_FRICTION = .01;

const double BALL_DIAMETER = 2.25; // 2.25 inche diameter 
const double BALL_MASS = 5.5; // ounces

const double STICK_LENGTH = 48; // 48 inches (minimum 40")
const double STICK_TIP_DIAMETER = .433; // 12mm (9mm - 14mm regulations)
const double STICK_END_DIAMETER = 1; // 1 inch

const double POCKET_CORNER_RADIUS = 4; // inches
const double POCKET_SIDE_RADIUS = 2.75; // inches

const double PRECISION = 100; // pixels per inch

const double PI = 3.14159265;

double Config::getRoomWidth()
{
   return ROOM_WIDTH * PRECISION;
}
double Config::getRoomDepth()
{
   return ROOM_DEPTH * PRECISION;
}
double Config::getRoomHeight()
{
   return ROOM_HEIGHT * PRECISION;
}
double Config::getTableLift()
{
   return TABLE_LIFT * PRECISION;
}

double Config::getTableWidth()
{
   return TABLE_WIDTH * PRECISION;
}
double Config::getTableDepth()
{
   return TABLE_DEPTH * PRECISION;
}
double Config::getTableHeight()
{
   return TABLE_HEIGHT * PRECISION;
}
double Config::getTableSlidingFriction()
{
   return TABLE_SLIDING_FRICTION;
}
double Config::getTableRollingFriction()
{
   return TABLE_ROLLING_FRICTION;
}
double Config::getBallDiameter()
{
   return BALL_DIAMETER * PRECISION;
}
double Config::getBallMass()
{
   return BALL_MASS;
}
double Config::getStickLength()
{
   return STICK_LENGTH * PRECISION;
}
double Config::getStickTipDiameter()
{
   return STICK_TIP_DIAMETER * PRECISION;
}
double Config::getStickEndDiameter()
{
   return STICK_END_DIAMETER * PRECISION;
}
double Config::getMaxSceneHeight()
{
   return getStickLength() + getBallDiameter();
}
double Config::getCornerPocketRadius()
{
   return POCKET_CORNER_RADIUS * PRECISION;
}
double Config::getSidePocketRadius()
{
   return POCKET_SIDE_RADIUS * PRECISION;
}

Textures* Config::getTextures()
{
   return textures;
}
Textures* Config::textures = new Textures();

const clock_t t1 = clock();

long Time::getTickCount()
{
#ifdef WIN32
	return GetTickCount();
#else
	clock_t t2 = clock();
	return long ((1000.0 * (t2 - t1)) / CLOCKS_PER_SEC);
#endif
}

Force::Force()
{
   angle = 180;
   velocity = 0;
}
Force::Force(double _angle, double _velocity)
{
   if (_angle >= 360)
      _angle -= 360;
   if (_angle < 0)
      _angle += 360;
   
   angle = _angle;
   double rAngle = angle * PI / 180.0;
   direction = Vec3f(sin(rAngle), 0, cos(rAngle));
   velocity = _velocity;
}
Vec3f Force::getDirection()
{
   return direction;
}
double Force::getVelocity()
{
   return velocity;
}

double Force::operator[] (unsigned index) const {return direction[index] * velocity;}
Force Force::operator* (double value) const
{
   return Force(angle, velocity * value);
}
Force Force::operator* (Force f) const
{
   double rAngle1 = PI/180.0 * angle;
   double rAngle2 = PI/180.0 * f.getAngle();

   double x = velocity*sin(rAngle1) + f.getVelocity()*sin(rAngle2);
   double z = velocity*cos(rAngle1) + f.getVelocity()*cos(rAngle2);
   
   double angle = atan(x/z) * 180.0/PI;
   if (z < 0)
      angle = 180 + angle;
   
   return Force(angle, sqrt(x*x + z*z));
}

double Force::getAngle()
{
   return angle;
}
